package withdraw

import (
	"context"
	"math"
	"strconv"
	"time"

	"gitee.com/liuxuezhan/ar-platform/assets-rpc/internal/dao/model/query"
	"gitee.com/liuxuezhan/ar-platform/assets-rpc/internal/dao/schema/config"
	schemaWithdraw "gitee.com/liuxuezhan/ar-platform/assets-rpc/internal/dao/schema/withdraw"
	"gitee.com/liuxuezhan/ar-platform/assets-rpc/internal/service"
	serviceWithdarw "gitee.com/liuxuezhan/ar-platform/assets-rpc/internal/service/withdraw"
	"gitee.com/liuxuezhan/ar-platform/assets-rpc/internal/svc"
	"gitee.com/liuxuezhan/ar-platform/assets-rpc/pkg/common"
	"gitee.com/liuxuezhan/ar-platform/assets-rpc/pkg/utils"
	"gitee.com/liuxuezhan/ar-platform/assets-rpc/pkg/utils/timeH"
	"gitee.com/liuxuezhan/ar-platform/assets-rpc/pkg/xerrors"
	"gitee.com/liuxuezhan/ar-platform/assets-rpc/rpc"
	"gitee.com/liuxuezhan/ar-platform/base-common/headInfo"
	"gitee.com/liuxuezhan/ar-platform/base-common/tool/wlog"
	"github.com/bytedance/sonic"
	"github.com/jinzhu/copier"
	"github.com/shopspring/decimal"
	"github.com/zeromicro/go-zero/core/logc"
	"github.com/zeromicro/go-zero/core/logx"
	"gorm.io/gorm"
)

type WithdrawModel struct {
	ctx context.Context
	db  *gorm.DB
	logx.Logger
	tx     *gorm.DB
	svcCtx *svc.ServiceContext
}

func NewWithdrawModel(ctx context.Context, svc *svc.ServiceContext) *WithdrawModel {
	return &WithdrawModel{
		svcCtx: svc,
		ctx:    ctx,
		db:     svc.Db,
		Logger: logx.WithContext(ctx),
	}
}
func (model *WithdrawModel) getDb() *gorm.DB {
	if model.db != nil {
		return model.db
	}

	return svc.Db
}
func (l *WithdrawModel) WithdrawFail(in *rpc.FailWithDrawReq) error {

	err := l.getDb().Transaction(func(tx *gorm.DB) error {
		g := query.Use(tx)
		h := g.WithdrawOrder.
			Where(g.WithdrawOrder.OrderNo.Eq(in.OrderNo))
		d, err := h.First()
		if err != nil {
			return xerrors.ErrWithDrawOrderNot
		}

		_, err = service.BalanceIncrease(l.ctx, l.svcCtx, &rpc.BalanceIncreaseRequest{
			UserId:   d.UserId,
			Amount:   d.OrderAmount,
			TypeId:   config.TYPE_WITHDRAWAL_CANCEL,
			SourceId: d.OrderNo,
		}, nil)
		if err != nil {
			return xerrors.ErrWithDrawOrderNotSave
		}

		d.Status = int32(rpc.WithDrawStatus_Fail)
		d.ReturnJson = in.Data
		d.LockerRemark = in.Err
		_, err2 := h.Updates(d)
		if err2 != nil {
			return xerrors.ErrWithDrawOrderNotSave
		}
		return nil
	})
	if err != nil {
		return err
	}
	return err
}

func (l *WithdrawModel) WithdrawListPage(in *rpc.FindWithDrawReq) (*rpc.FindWithDrawRes, error) {
	ret := &rpc.FindWithDrawRes{
		ResHead: nil,
		Data:    nil,
		Page:    &rpc.Pagination{},
	}
	g := query.Use(l.getDb()).WithdrawOrder
	h := g.Where(g.Status.In(
		int32(rpc.WithDrawStatus_Success),
		int32(rpc.WithDrawStatus_Fail),
		int32(rpc.WithDrawStatus_Pass),
		int32(rpc.WithDrawStatus_Refuse)))
	if in.OrderNo != "" {
		h = h.Where(g.OrderNo.Eq(in.OrderNo))
	} else {
		if in.Locker != "" {
			h = h.Where(g.Locker.Eq(in.Locker))

		}
		if in.UserId != 0 {
			h = h.Where(g.UserId.Eq(in.UserId))
		}
		if in.Type != 0 {
			h = h.Where(g.ChannelType.Eq(in.Type))
		}
		if in.Status != int32(rpc.WithDrawStatus_Default) {
			h = h.Where(g.Status.Eq(in.Status))
		}

		if in.MixAmount < in.MaxAmount && in.MixAmount != 0 && in.MaxAmount != 0 {
			h = h.Where(g.OrderAmount.Between(in.MixAmount, in.MaxAmount))
		}
		if in.CreateStartTm < in.CreateEndTm && in.CreateStartTm != 0 && in.CreateEndTm != 0 {
			h = h.Where(g.CreatedAt.Between(in.CreateStartTm, in.CreateEndTm))
		}
		if in.FinishStartTm < in.FinishEndTm && in.FinishStartTm != 0 && in.FinishEndTm != 0 {
			h = h.Where(g.UpdatedAt.Between(in.FinishStartTm, in.FinishEndTm))
		}
	}
	h = h.Order(g.CreatedAt.Desc())
	var err2 error
	if in.Page != nil {
		if in.Page.Page <= 0 {
			in.Page.Page = 1
		}
		if in.Page.PageSize <= 0 {
			in.Page.PageSize = 10
		}
		ret.Page.Page = uint32(in.Page.Page)
		ret.Page.PageSize = uint32(in.Page.PageSize)
	}
	ret.Page.Total, ret.Data, err2 = l.WidrawOrderList(in.Page, h)
	ret.Page.TotalPage = int64(math.Ceil(float64(ret.Page.Total) / float64(ret.Page.PageSize)))
	if err2 != nil {
		return ret, err2
	}
	return ret, nil
}
func (l *WithdrawModel) WithdrawLockListPage(in *rpc.WithdrawLockListPageReq) (*rpc.WithdrawLockListPageRes, error) {
	ret := &rpc.WithdrawLockListPageRes{
		ResHead: nil,
		Data:    nil,
		Page:    &rpc.Pagination{},
	}
	g := query.Use(l.getDb()).WithdrawOrder
	h := g.Where(g.Status.In(int32(rpc.WithDrawStatus_UnLock), int32(rpc.WithDrawStatus_Lock)))
	if in.UserId != 0 {
		h = h.Where(g.UserId.Eq(in.UserId))
	}
	if in.Type != 0 {
		h = h.Where(g.ChannelType.Eq(in.Type))
	}
	if in.MixAmount < in.MaxAmount && in.MixAmount != 0 && in.MaxAmount != 0 {
		h = h.Where(g.OrderAmount.Between(in.MixAmount, in.MaxAmount))
	}
	if in.StartTm < in.EndTm && in.StartTm != 0 && in.EndTm != 0 {
		h = h.Where(g.CreatedAt.Between(in.StartTm, in.EndTm))
	}
	var err2 error

	if in.Page.Page <= 0 {
		in.Page.Page = 1
	}
	if in.Page.PageSize <= 0 {
		in.Page.PageSize = 10
	}
	ret.Page.Page = uint32(in.Page.Page)
	ret.Page.PageSize = uint32(in.Page.PageSize)
	ret.Page.Total, ret.Data, err2 = l.WidrawOrderList(in.Page, h)
	ret.Page.TotalPage = int64(math.Ceil(float64(ret.Page.Total) / float64(ret.Page.PageSize)))
	if err2 != nil {
		return ret, err2
	}
	return ret, nil
}

func (l *WithdrawModel) WidrawOrderList(in *rpc.Page, h query.IWithdrawOrderDo) (count int64, ret []*rpc.WithdrawInfo, err error) {
	var d []*schemaWithdraw.WithdrawOrder
	g := query.Use(l.getDb())

	if in != nil {
		if in.Page <= 0 {
			in.Page = 1
		}
		if in.PageSize <= 0 {
			in.PageSize = 10
		}

		if in.SortOrder == "asc" {
			h = h.Order(g.WithdrawOrder.CreatedAt.Asc())
		} else {
			h = h.Order(g.WithdrawOrder.CreatedAt.Desc())

		}
		count, err = h.Count()
		if err != nil {
			return
		}
		d, _, err = h.FindByPage(int((in.Page-1)*in.PageSize), int(in.PageSize))
	} else {
		count, err = h.Count()
		if err != nil {
			return
		}
		d, err = h.Order(g.WithdrawOrder.CreatedAt.Desc()).Find()
	}

	if err != nil {
		return
	}
	for i, _ := range d {
		item := &rpc.WithdrawInfo{}
		copier.Copy(item, d[i])
		err2 := l.WithdrawGetUserInfo(item)
		channel := []*schemaWithdraw.WithdrawChannel{}
		if err2 != nil && d[i].Status != int32(rpc.WithDrawStatus_Refuse) {
			mark := "WithdrawGetUserInfo err"
			l.WithdrawRefuse(&rpc.RefuseWithDrawReq{
				OrderNos: d[i].OrderNo,
				Remark:   mark,
			})
			item.Status = int32(rpc.WithDrawStatus_Refuse)
			item.LockerRemark = mark
		} else {
			if item.WithdrawChannelId != 0 {
				channel, err2 = g.WithdrawChannel.Where(g.WithdrawChannel.ID.Eq(item.WithdrawChannelId)).Find()
			} else {
				channel, err2 = g.WithdrawChannel.Where(g.WithdrawChannel.Type.Eq(item.ChannelType)).Find()
			}
			if err2 != nil && d[i].Status != int32(rpc.WithDrawStatus_Refuse) {
				mark := "WithdrawChannel err"
				l.WithdrawRefuse(&rpc.RefuseWithDrawReq{
					OrderNos: d[i].OrderNo,
					Remark:   mark,
				})
				item.Status = int32(rpc.WithDrawStatus_Refuse)
				item.LockerRemark = mark
			}
		}

		item.Channel = map[int64]*rpc.WithdrawChannel{}
		for i2, _ := range channel {
			if d[i].RealAmount >= channel[i2].MinAmount &&
				d[i].RealAmount <= channel[i2].MaxAmount &&
				channel[i2].Status == int32(rpc.WithdrawStatus_Open) {
				item.Channel[channel[i2].ID] = &rpc.WithdrawChannel{}
				copier.Copy(item.Channel[channel[i2].ID], channel[i2])
			}
		}

		ret = append(ret, item)
	}
	// if len(req2.UserIds) != 0 {
	// 	d2, err2 := l.svcCtx.UserRpc.UserGetAccountsByIds(l.ctx, req2)
	// 	if err2 != nil {
	// 		err = err2
	// 	} else {
	// 		for i, _ := range ret {
	// 			for _, user := range d2.GetAccounts() {
	// 				if user.GetUserId() == ret[i].GetLockerId() {
	// 					ret[i].Locker = user.GetNickname()
	// 					break
	// 				}
	// 			}
	// 		}
	// 	}
	// }

	return
}

func (l *WithdrawModel) WithdrawPayListPage(in *rpc.WithdrawPayListPageReq) (*rpc.WithdrawPayListPageRes, error) {
	ret := &rpc.WithdrawPayListPageRes{
		ResHead: nil,
		Data:    nil,
		Page:    &rpc.Pagination{},
	}
	g := query.Use(l.getDb()).WithdrawOrder
	h := g.Where(g.Status.Eq(int32(rpc.WithDrawStatus_Lock)))
	if in.OrderNo != "" {
		h = h.Where(g.OrderNo.Eq(in.OrderNo))
	} else {
		if in.Locker != "" {
			h = h.Where(g.Locker.Eq(in.Locker))
		}
		if in.UserId != 0 {
			h = h.Where(g.UserId.Eq(in.UserId))
		}
		if in.Type != 0 {
			h = h.Where(g.ChannelType.Eq(in.Type))
		}

		if in.MixAmount < in.MaxAmount && in.MixAmount != 0 && in.MaxAmount != 0 {
			h = h.Where(g.OrderAmount.Between(in.MixAmount, in.MaxAmount))
		}
		if in.StartTm < in.EndTm && in.StartTm != 0 && in.EndTm != 0 {
			h = h.Where(g.CreatedAt.Between(in.StartTm, in.EndTm))
		}
	}
	var err error

	// ret.Page.Page = uint32(in.Page.Page)
	// ret.Page.PageSize = uint32(in.Page.PageSize)
	ret.Page.Total, ret.Data, err = l.WidrawOrderList(in.Page, h)
	ret.Page.TotalPage = int64(math.Ceil(float64(ret.Page.Total) / float64(ret.Page.PageSize)))
	if err != nil {
		return ret, err
	}
	return ret, nil
}

func (l *WithdrawModel) Withdraw(in *rpc.UserWithDrawReq) (*rpc.UserWithDrawRes, error) {
	ret := &rpc.UserWithDrawRes{}
	err := serviceWithdarw.NewWithdrawService(l.ctx, l.svcCtx).VerifyMarkConsume(in.UserId)
	if err != nil {
		logc.Error(l.ctx, "ErrConsumeMustGreaterEqualMark,err", err)
		return nil, xerrors.ErrConsumeMustGreaterEqualMark
	}

	withdraw := &schemaWithdraw.WithdrawOrder{ // 创建提现订单
		UserId:                in.UserId,
		ChannelType:           in.WithdrawTypeId,
		WithdrawUserChannelId: in.WithdrawUserChannelId,
		OrderAmount:           in.Amount,
		Status:                int32(rpc.WithDrawStatus_UnLock),
		OrderNo:               utils.GenerateOrderId("WD"),
		Domain:                headInfo.GetReqHost(l.ctx),
	}
	r2 := decimal.NewFromFloat(1)
	// if withdraw.ChannelType == int32(rpc.ChannelType_ChannelTypeUsdtWallets) {
	// 	withdraw.Ratio = float64(serviceWithdarw.IsOpen(l.svcCtx, l.ctx, common.USDT, "withdraw"))
	// 	if withdraw.Ratio != 0 {
	// 		r2 = decimal.NewFromFloat(withdraw.Ratio)
	// 	}
	// }

	err = l.getDb().Transaction(func(tx *gorm.DB) error {
		g := query.Use(tx)
		d2, err := g.WithdrawType.Where(g.WithdrawType.Type.Eq(in.WithdrawTypeId)).First()
		if err != nil {
			return err
		}
		src := decimal.NewFromFloat(withdraw.OrderAmount)
		fee := src.Mul(decimal.NewFromFloat(d2.FeeRate))
		tmp := src.Sub(fee)
		withdraw.Real, _ = tmp.RoundCeil(10).Float64()
		d3, err2 := g.VirtualDic.Where(g.VirtualDic.CoinName.Eq(d2.FromCion)).First()
		if err2 == nil {
			withdraw.Ratio = d3.ToRate
			r2 = decimal.NewFromFloat(withdraw.Ratio)
		}
		tmp = tmp.Div(r2)
		withdraw.RealAmount, _ = tmp.RoundCeil(10).Float64()
		withdraw.Fee = withdraw.OrderAmount - withdraw.Real
		result := tx.Create(withdraw)
		if err := result.Error; err != nil {
			return err
		}
		if result.RowsAffected == 0 {
			return xerrors.ErrRechargeOrderProcessed
		}
		_, err = service.BalanceDecrease(l.ctx, l.svcCtx, &rpc.BalanceDecreaseRequest{
			UserId:   in.UserId,
			Amount:   withdraw.OrderAmount,
			TypeId:   config.TYPE_WITHDRAWAL,
			SourceId: withdraw.OrderNo,
		})
		if err != nil {
			return err
		}

		return nil
	})

	if err != nil {
		return nil, err
	}
	ret.Data = &rpc.WithdrawInfo{}
	copier.Copy(ret.Data, withdraw)
	err = serviceWithdarw.AddNotificationMessageToCReq(l.svcCtx, l.ctx, in.UserId, 3)
	if err != nil {
		wlog.Handle.Error(nil, "[%s]", err.Error())
	}
	return ret, nil
}

func (l *WithdrawModel) WithdrawPass(in *rpc.PassWithDrawReq) (*rpc.PassWithDrawRes, error) {
	ret := &rpc.PassWithDrawRes{}
	g := query.Use(l.getDb())

	order := g.WithdrawOrder.
		Where(g.WithdrawOrder.OrderNo.Eq(in.OrderNo)).
		Where(g.WithdrawOrder.Status.Eq(int32(rpc.WithDrawStatus_Lock)))
	d, err := order.First()
	if err != nil {
		return nil, xerrors.ErrWithDrawOrderNot
	}

	if in.ChannelId != 0 { // 非人工确认
		channel, err3 := g.WithdrawChannel.Where(g.WithdrawChannel.ID.Eq(in.ChannelId)).First()
		if err3 != nil || channel == nil {
			return nil, xerrors.ErrWithDrawChannelNot
		}
		ret.Order = &rpc.WithdrawInfo{}
		copier.Copy(ret.Order, d)
		ret.Order.Channel = map[int64]*rpc.WithdrawChannel{}
		ret.Order.Channel[channel.ID] = &rpc.WithdrawChannel{}
		copier.Copy(ret.Order.Channel[channel.ID], channel)
		err2 := l.WithdrawGetUserInfo(ret.Order)
		if err2 != nil {
			return nil, err2
		}
		d.WithdrawChannelId = in.ChannelId
		d.Status = int32(rpc.WithDrawStatus_Pass)
	} else {
		d.WithdrawChannelId = int64(rpc.ChannelType_ChannelTypeSuccess)
		d.Status = int32(rpc.WithDrawStatus_Success)
	}
	_, err2 := order.UpdateColumns(map[string]interface{}{
		"locker_remark":       in.Remark,
		"status":              d.Status,
		"withdraw_channel_id": d.WithdrawChannelId,
	})
	if err2 != nil {
		return nil, xerrors.ErrWithDrawOrderNot
	}
	if in.ChannelId == 0 {
		l.WithdrawSuccess(&rpc.SuccessWithDrawReq{
			OrderNo: in.OrderNo,
		})
	}
	return ret, nil
}

func (l *WithdrawModel) WithdrawGetUserInfo(ret *rpc.WithdrawInfo) error {
	g := query.Use(l.getDb())
	if ret.ChannelType == int32(rpc.ChannelType_ChannelTypeBank) && ret.WithdrawUserChannelId > 0 {
		h := g.UserChannelBank.Where(g.UserChannelBank.ID.Eq(ret.WithdrawUserChannelId))
		user_channel, err4 := h.First()
		if err4 != nil {
			return xerrors.ErrUserChannelBankNot
		}
		bank, err5 := g.ConfigBank.Where(g.ConfigBank.ID.Eq(user_channel.BankId)).First()
		if err5 != nil { // 银行id有问题
			h.Delete()
			return xerrors.ErrUserChannelBankNot
		}
		ret.UserBank = &rpc.UserBankInfo{
			UserId:     user_channel.UserId,
			UserName:   user_channel.UserName,
			CardNumber: user_channel.CardNumber,
			IfscCode:   user_channel.IfscCode,
			Phone:      user_channel.Phone,
			Email:      user_channel.Email,
			Province:   user_channel.Province,
			City:       user_channel.City,
			BranchBank: user_channel.BranchBank,
			Id:         user_channel.ID,
			BankCode:   bank.BankCode,
			BankName:   bank.BankName,
		}
	}
	if ret.ChannelType == int32(rpc.ChannelType_ChannelTypeEwallet) && ret.WithdrawUserChannelId > 0 {
		user_channel, err4 := g.UserChannelEwallet.Where(g.UserChannelEwallet.ID.Eq(ret.WithdrawUserChannelId)).First()
		if err4 != nil {
			return xerrors.ErrUserChannelEwalletNot
		}
		ret.UserEwallets = &rpc.UserEWalletsInfo{
			UserId:     user_channel.UserId,
			WalletName: user_channel.Name,
			Username:   user_channel.Username,
			Account:    user_channel.Account,
			Id:         user_channel.ID,
		}
	}
	if ret.ChannelType == int32(rpc.ChannelType_ChannelTypeLocalEwallet) && ret.WithdrawUserChannelId > 0 {
		user_channel, err4 := g.UserChannelLocalEwallet.Where(g.UserChannelLocalEwallet.ID.Eq(ret.WithdrawUserChannelId)).First()
		if err4 != nil {
			return xerrors.ErrUserChannelLocalEwalletNot
		}
		ret.UserLocalEwallets = &rpc.UserLocalEwalletInfo{
			UserId:           user_channel.UserId,
			Id:               user_channel.ID,
			Owner:            user_channel.Owner,
			Phone:            user_channel.Phone,
			Code:             user_channel.Code,
			RevenueMin:       user_channel.RevenueMin,
			RevenueMax:       user_channel.RevenueMax,
			FixedDailyLimit:  int64(user_channel.FixedDailyLimit),
			RemainDailyLimit: int64(user_channel.RemainDailyLimit),
			IncomeDailyLimit: int64(user_channel.IncomeDailyLimit),
			DailyLimit:       user_channel.DailyLimit,
		}
	}
	if ret.ChannelType == int32(rpc.ChannelType_ChannelTypePixWallets) && ret.WithdrawUserChannelId > 0 {
		user_channel, err4 := g.UserChannelPix.Where(g.UserChannelPix.ID.Eq(ret.WithdrawUserChannelId)).First()
		if err4 != nil {
			return xerrors.ErrUserChannelPixNot
		}
		ret.UserPixWallets = &rpc.UserPixWalletsInfo{
			UserId:     user_channel.UserId,
			Id:         user_channel.ID,
			WalletType: user_channel.WalletType,
			Username:   user_channel.UserName,
			Cpf:        user_channel.Cpf,
			Account:    user_channel.Account,
		}
	}
	if ret.ChannelType == int32(rpc.ChannelType_ChannelTypeUsdtWallets) && ret.WithdrawUserChannelId > 0 {
		user_channel, err4 := g.UserChannelUsdt.Where(g.UserChannelUsdt.ID.Eq(ret.WithdrawUserChannelId)).First()
		if err4 != nil {
			return xerrors.ErrUserChannelUsdtNot
		}
		ret.UserUsdtWallets = &rpc.UserUsdtWalletsInfo{
			UserId:   user_channel.UserId,
			Id:       user_channel.ID,
			UsdtType: user_channel.UsdtType,
			Address:  user_channel.Address,
		}
	}
	return nil
}

func (l *WithdrawModel) WithdrawRefuse(in *rpc.RefuseWithDrawReq) (ret *rpc.RefuseWithDrawRes, err error) {
	ret = &rpc.RefuseWithDrawRes{}
	err = l.getDb().Transaction(func(tx *gorm.DB) error {
		l.tx = tx
		g := query.Use(tx).WithdrawOrder
		h := g.Where(g.OrderNo.Eq(in.OrderNos))
		d, err := h.First()
		if err != nil {
			return xerrors.ErrWithDrawOrderNot
		}

		_, err = service.BalanceIncrease(l.ctx, l.svcCtx, &rpc.BalanceIncreaseRequest{
			UserId:   d.UserId,
			Amount:   d.OrderAmount,
			TypeId:   config.TYPE_WITHDRAWAL_CANCEL,
			SourceId: d.OrderNo,
		}, nil)
		if err != nil {
			return xerrors.ErrWithDrawOrderNotSave
		}
		_, err = h.UpdateColumns(map[string]interface{}{
			"locker_remark": in.Remark,
			"status":        rpc.WithDrawStatus_Refuse,
		})
		if err != nil {
			return err
		}

		m2 := NewTypeModel(l.ctx, l.svcCtx)
		err = m2.WithdrawDailyTimesAdd(d.ChannelType)
		if err != nil {
			return err
		}
		ret.Data = &rpc.WithdrawInfo{
			OrderNo: in.OrderNos,
			Status:  int32(rpc.WithDrawStatus_Refuse),
		}
		return nil
	})
	return
}

func (l *WithdrawModel) WithdrawSuccess(in *rpc.SuccessWithDrawReq) (*rpc.SuccessWithDrawRes, error) {
	ret := &rpc.SuccessWithDrawRes{}
	err := l.getDb().Transaction(func(tx *gorm.DB) error {
		l.tx = tx
		g := query.Use(tx)
		h := g.WithdrawOrder.Where(g.WithdrawOrder.OrderNo.Eq(in.OrderNo))
		d, err := h.First()
		if err != nil {
			return err
		}
		d.Status = int32(rpc.WithDrawStatus_Success)
		d.ReturnJson = in.Data
		_, err2 := h.Updates(d)
		if err2 != nil {
			return err2
		}
		// 减余额
		_, err = service.BalanceDecrease(l.ctx, l.svcCtx, &rpc.BalanceDecreaseRequest{
			UserId:        d.UserId,
			Amount:        0,
			TypeId:        config.TYPE_WITHDRAWAL,
			TotalWithdraw: d.OrderAmount,
		})

		if err != nil {
			return err
		}
		ret.UserId = d.UserId
		ret.Amount = d.OrderAmount
		ret.OrderNo = d.OrderNo
		ret.Tm = d.CreatedAt
		ret.TypeId = config.TYPE_WITHDRAWAL
		d2, err := g.WithdrawType.Where(g.WithdrawType.Type.Eq(d.ChannelType)).First()
		if err == nil {
			ret.Code = d2.FromCion
		}
		return nil
	})
	if err != nil {
		return nil, err
	}
	// 推送 kafka 消息
	if ret != nil {
		s, _ := sonic.MarshalString(ret)
		if err = utils.SendKafkaMessage(rpc.KafkaTopic_name[int32(rpc.KafkaTopic_KafkaTopicWithdraw)], l.ctx, l.svcCtx, s); err != nil {
			logc.Error(l.ctx, err)
		}
		serviceWithdarw.AddNotificationMessageToCReq(l.svcCtx, l.ctx, ret.UserId, 4)

	}
	return ret, nil
}
func (l *WithdrawModel) WithdrawOrderIdUpdate(in *rpc.WithdrawOrderIdUpdateReq) (*rpc.WithdrawOrderIdUpdateRes, error) {
	ret := &rpc.WithdrawOrderIdUpdateRes{}
	g := query.Use(l.db)

	h := g.WithdrawOrder.Where(g.WithdrawOrder.OrderNo.Eq(in.OrderNo))
	d, err := h.First()
	if err != nil {
		return nil, xerrors.ErrWithDrawOrderNot
	}
	d.OrderId = (in.OrderId)
	_, err2 := h.Updates(d)
	if err2 != nil {
		return nil, xerrors.ErrWithDrawOrderNotSave
	}
	return ret, nil
}
func (l *WithdrawModel) WithdrawLock(in *rpc.LockWithDrawReq) (*rpc.LockWithDrawRes, error) {

	ret := &rpc.LockWithDrawRes{}
	err := l.getDb().Transaction(func(tx *gorm.DB) error {
		g := query.Use(tx).WithdrawOrder
		for i, _ := range in.OrderNos {
			d, err2 := g.
				Where(g.OrderNo.Eq(in.OrderNos[i])).
				// Where(g.Status.Eq(int32(rpc.WithDrawStatus_UnLock))).
				First()
			if err2 != nil {
				return xerrors.ErrWithDrawOrderNot
			} else {
				if d.Status != int32(rpc.WithDrawStatus_Fail) && d.Status != int32(rpc.WithDrawStatus_Pass) {
					if d.Status == int32(rpc.WithDrawStatus_Lock) || d.Status != int32(rpc.WithDrawStatus_UnLock) {
						// 已经锁定或者状态未解锁
						continue
					}
				}

				d2 := map[string]interface{}{
					"locker":              in.Locker,
					"status":              rpc.WithDrawStatus_Lock,
					"withdraw_channel_id": 0,
				}
				_, err := g.Where(g.ID.Eq(d.ID)).Updates(d2)
				if err != nil {
					return xerrors.ErrWithDrawOrderNotSave
				}
			}
			ret.Data = append(ret.Data, &rpc.WithdrawInfo{
				OrderNo: d.OrderNo,
				Status:  d.Status,
			})
		}

		return nil
	})
	if err != nil {
		return nil, err
	}
	// ------------------------------------第三方支付(异步回调)----------------------------------------------
	return ret, nil
}
func (l *WithdrawModel) WithdrawUnlock(in *rpc.UnlockWithDrawReq) (*rpc.UnlockWithDrawRes, error) {

	ret := &rpc.UnlockWithDrawRes{}
	err := l.getDb().Transaction(func(tx *gorm.DB) error {
		g := query.Use(tx).WithdrawOrder
		for i, _ := range in.OrderNos {
			d, err := g.
				Where(g.OrderNo.Eq(in.OrderNos[i])).
				First()
			if err != nil {
				return xerrors.ErrWithDrawOrderNot
			} else {
				if d.Status == int32(rpc.WithDrawStatus_UnLock) || d.Status != int32(rpc.WithDrawStatus_Lock) {
					continue
				}
				_, err = g.Where(g.ID.Eq(d.ID)).UpdateSimple(g.Locker.Value(""),
					g.Status.Value(int32(rpc.WithDrawStatus_UnLock)),
					g.WithdrawChannelId.Value(0))
				if err != nil {
					return xerrors.ErrWithDrawOrderNotSave
				}
			}
			ret.Data = append(ret.Data, &rpc.WithdrawInfo{
				OrderNo: strconv.FormatInt(d.ID, 10),
				Status:  d.Status,
			})
		}

		return nil
	})
	if err != nil {
		return nil, err
	}
	// -----
	return ret, nil
}
func (l *WithdrawModel) WithdrawUserListPage(in *rpc.UserFindWithDrawReq) (*rpc.UserFindWithDrawRes, error) {
	ret := &rpc.UserFindWithDrawRes{
		ResHead: nil,
		Data:    nil,
		Page:    &rpc.Pagination{},
	}

	g := query.Use(l.getDb()).WithdrawOrder
	h := g.Where(g.UserId.Eq(in.UserId))
	if in.Status != 0 {
		// 兼容前端接口传参只有 3, 4, 5 三种状态
		switch in.Status {
		case 3:
			h = h.Where(g.Status.In(1, 2, 3))
		case 4:
			h = h.Where(g.Status.In(4, 6))
		default:
			h = h.Where(g.Status.Eq(in.Status))
		}
	}
	if in.Channel != 0 {
		h = h.Where(g.ChannelType.Eq(in.Channel))
	}
	if in.TmStart < in.TmEnd && in.TmStart != 0 && in.TmEnd != 0 {
		h = h.Where(g.CreatedAt.Between(in.TmStart, in.TmEnd))
	}
	h = h.Order(g.CreatedAt.Desc())
	var err2 error
	ret.Page.Page = uint32(in.Page.Page)
	ret.Page.PageSize = uint32(in.Page.PageSize)

	day := serviceWithdarw.IsOpen(l.svcCtx, l.ctx, common.WithdrawOrder, "numerical")
	if day != 0 {
		h = h.Where(g.CreatedAt.Gt(time.Now().AddDate(0, 0, int(-day)).Unix()))
	}
	ret.Page.Total, ret.Data, err2 = l.WidrawOrderList(in.Page, h)
	ret.Page.TotalPage = int64(math.Ceil(float64(ret.Page.Total) / float64(ret.Page.PageSize)))
	if err2 != nil {
		return ret, err2
	}
	return ret, nil
}

func (l *WithdrawModel) FindUserWithdrawCountMap(userId int64, t time.Time) map[int32]int64 {
	var (
		res   = make(map[int32]int64)
		dbRes []struct {
			TypeId int32 `json:"type_id"`
			Count  int64 `json:"count"`
		}
	)
	ormRes := l.getDb().Model(&schemaWithdraw.WithdrawOrder{}).
		Select(
			"channel_type as `type_id`",
			"count(*) as `count`",
		).
		Where("user_id = ?", userId).
		Where("created_at >= ?", timeH.DayStartTime(t).Unix()).
		Group("channel_type").
		Find(&dbRes)
	if ormRes.Error != nil {
		logc.Error(l.ctx, ormRes.Error)
		return res
	}

	for i := range dbRes {
		res[dbRes[i].TypeId] = dbRes[i].Count
	}

	return res
}
